package com.mamba.microservice.dubbo.filter;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.mamba.microservice.dubbo.enums.EnumStatus;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import com.mamba.microservice.log.*;
/**
 * Copyright ©2020 360jinrong All Rights Reserved
 * 请添加类/接口的说明:Dubbo分布式日志追踪
 * 打印dubbo调用的io和monitor日志
 *
 * @Package: com.mamba.microservice.dubbo.log
 * @author: fangjin
 * @date: 2020年04月20日 14时37分
 */
@Slf4j
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER})
public class MmsDubboTraceFilter implements Filter {
    /**
     * |consumer-app|localIp|provider-app|remote-ip|interfaceName#methodName|status|costs|
     */
    private static final String CONSUMER_MONITOR_LOG_PATTERN = "|{}|{}|{}|{}|{}|{}|{}ms|";
    /**
     * |localIp|provider-app|interfaceName#methodName|status|costs|
     */
    private static final String PROVIDER_MONITOR_LOG_PATTERN = "|{}|{}|{}|{}|{}ms|";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        log.debug("[mms-dubbo] logger record filter start");
        long startMillis = System.currentTimeMillis();
        boolean isFailed = false;

        Result result = null;
        try {
            result = invoker.invoke(invocation);
            return result;
        } catch (Exception e) {
            log.error("Invoke exception.", e);
            isFailed = true;
            throw e;
        } finally {
            long costsMillis = System.currentTimeMillis() - startMillis;
            printMonitorLog(invoker, invocation, costsMillis, isFailed);
            printIoLogger(invoker, invocation, result);
        }
    }

    @Override
    public Result onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        return null;
    }

    /**
     * 构建io日志
     *
     * @param invoker
     * @param invocation
     * @param result
     * @return
     */
    private void printIoLogger(Invoker<?> invoker, Invocation invocation, Result result) {
        String interfaceName = invoker.getInterface().getName();
        String methodName = invocation.getMethodName();
        Object[] arguments = invocation.getArguments();
        String argumentsString = JSON.toJSONString(arguments, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);

        String resultString = null;
        if (result != null && !result.hasException()) {
            resultString = JSON.toJSONString(result.getValue(), SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);
        }
        MmsInputOutLogger.logInputOutput(LogInputOutputDomain.builder()
                .methodSignature(interfaceName + "#" + methodName)
                .argumentsString(argumentsString)
                .resultString(resultString)
                .build());

    }

    private boolean isConsumerSide(Invoker<?> invoker) {
        return invoker.getUrl().getParameter(Constants.SIDE_KEY, Constants.PROVIDER_SIDE).equals(Constants.CONSUMER_SIDE);
    }

    private void printMonitorLog(Invoker<?> invoker, Invocation invocation, long costsMillis, boolean isFailed) {
        String application = invoker.getUrl().getParameter(CommonConstants.APPLICATION_KEY);

        String interfaceName = invoker.getInterface().getName();
        String methodName = invocation.getMethodName();
        String status = isFailed ? EnumStatus.FAIL.getCode() : EnumStatus.SUCCESS.getCode();
        RpcContext context = RpcContext.getContext();
        String remoteHost = context.getRemoteHost();
        LogMonitorDomain logMonitor = LogMonitorDomain.builder().methodSignature(interfaceName + "#" + methodName).status(status).costMills(costsMillis).build();

        if (isConsumerSide(invoker)) {
            String remoteApplication = invoker.getUrl().getParameter(CommonConstants.REMOTE_APPLICATION_KEY);
            logMonitor.setConsumerApplication(application);
            logMonitor.setConsumerIp("127.0.0.1");//todo 本地机器ip
            logMonitor.setProviderApp(remoteApplication);
            logMonitor.setProviderIp(remoteHost);
            logMonitor.setPattern(CONSUMER_MONITOR_LOG_PATTERN);
            MmsConsumerMonitorLogger.monitorConsumerLog(logMonitor);
        } else {
            logMonitor.setProviderIp("127.0.0.1");
            logMonitor.setProviderApp(application);//todo 本地机器ip
            logMonitor.setPattern(PROVIDER_MONITOR_LOG_PATTERN);
            MmsProviderMonitorLogger.monitorProviderLog(logMonitor);
        }
    }
}
